<!-- 参会人员 -->
<template>
  <app-page card full>
    <template #header>参会人员</template>

    <div class="meet-user-main">
      <div class="meet-user-main__search">
        <div class="meet-user-main__search--input">
          <div class="app-flex-mid search-wrapper">
            <el-input v-model="data.userName" placeholder="请输入参会人员姓名" />
            <div class="app-flex-mid">
              <el-button type="primary" @click="handleSearch()">搜索</el-button>
              <el-button type="primary" @click="handleSearch('reset')">重置</el-button>
            </div>
          </div>
          <div class="app-flex-mid btn-wrapper">
            <DownloadTemplate file-name="参会人员.xlsx" />
            <ImportUpload :attr="{ type: 'success', icon: '', plain: true }" @change="onChange" />
            <el-button :loading="exportLoading" type="warning" plain @click="handleExport">导出</el-button>
            <el-button type="primary" @click="data.show = true">添加</el-button>
            <div class="total-wrapper">共计：{{ data.list?.length || 0 }}人</div>
          </div>
        </div>
        <div class="meet-user-main__search--list">
          <el-table
            v-click-outside="cleanSelected"
            ref="tableRef"
            class="table-wrapper"
            :loading="pageData.loading"
            :data="data.list"
            highlight-current-row
            height="500"
            @current-change="handleCurrentChange"
          >
            <el-table-column prop="mobile" label="手机号" />
            <el-table-column prop="name" label="人员姓名" />
            <el-table-column prop="jobTitle" :formatter="onFormatter">
              <template #header>
                <div class="app-flex-mid job-switch">
                  <span>职务</span>
                  <el-switch
                    class="job-switch__btn"
                    style="--el-switch-off-color: #ccc"
                    v-model="pageData.detail.showJobTitle"
                  />
                </div>
              </template>
            </el-table-column>
            <el-table-column
              prop="company"
              label="所属单位"
              :show-overflow-tooltip="{ popperClass: 'app-table-tooltip' }"
            />
            <el-table-column prop="role" label="参会角色" />
            <el-table-column label="操作" width="70">
              <template #default="{ row }">
                <el-button type="primary" link @click.stop="handleDelete(row)">删除</el-button>
              </template>
            </el-table-column>
          </el-table>
        </div>
      </div>
      <div class="meet-user-main__right-body">
        <div class="location-header app-flex-space-between">
          <div class="app-flex-mid export-wrapper">
            <span>拖拽可以调整位置</span>
            <el-button type="warning" plain @click="handleResults" :loading="data.locationLoading">
              导出位次图
            </el-button>
          </div>
          <el-text type="primary" class="contain-total">最大容纳：{{ data.maxRow * data.maxCol }}人</el-text>
        </div>
        <div class="meet-user-main__location">
          <div class="meet-user-main__location--area">
            <div
              class="area-wrapper"
              :style="{
                '--location-column': data.maxCol,
                '--location-row': data.maxRow,
              }"
              ref="locationRef"
            >
              <div class="area-wrapper--top">
                <div class="area-wrapper--top-locale" v-for="order in data.maxCol" :key="order">
                  {{ order }}列
                </div>
              </div>
              <div class="area-wrapper--left">
                <div class="area-wrapper--left-locale" v-for="order in data.maxRow" :key="order">
                  {{ order }}排
                </div>
              </div>
              <draggable
                tag="div"
                class="meet-user-main__location-wrapper"
                :style="{
                  'justify-content': data.maxCol > 22 ? 'flex-start' : 'center',
                  width: data.maxCol > 22 ? 'fit-content' : 'auto',
                }"
                :options="{ animation: 300 }"
                v-model="gridCells"
                item-key="id"
                @end="onDragEnd"
              >
                <template #item="{ element }">
                  <div
                    :class="[
                      'ellipsis location-wrapper-square',
                      data.curSelected?.seatRow === element.seatRow &&
                        data.curSelected?.seatCol === element.seatCol &&
                        'current-row',
                    ]"
                    :title="`第${element.seatRow}排，第${element.seatCol}列`"
                  >
                    {{ element.name }}
                  </div>
                </template>
              </draggable>
            </div>
          </div>
        </div>
        <div class="location-footer" v-if="data.curSelected?.name">
          {{ data.curSelected?.name }} {{ `${data.curSelected?.seatRow}排${data.curSelected?.seatCol}列` }}
        </div>
      </div>
    </div>

    <template #footer>
      <div class="app-toolbar">
        <el-button type="default" @click="pageActions.handleCancel()">返回</el-button>
        <el-button type="primary" @click="pageActions.handleDirectSubmit(true, true)">保存</el-button>
      </div>
    </template>
  </app-page>

  <AddDialog v-model="data.show" @confirm="handleAddConfirm" />
</template>

<script setup>
import ImportUpload from '@/components/form/ImportUpload.vue'
import DownloadTemplate from '@/components/form/DownloadTemplate.vue'
import draggable from 'vuedraggable'
import { ClickOutside, ElMessage, ElMessageBox, dayjs } from 'element-plus'
import { usePageEdit, http } from 'jax-node'
import AddDialog from './components/AddDialog.vue'
import html2canvas from 'html2canvas'

const vClickOutside = ClickOutside

const { pageData, pageActions } = usePageEdit({
  api: 'meet/user',
})

const onFormatter = (row, column, cellValue) => {
  return cellValue ? cellValue : '/'
}

const data = reactive({
  userName: '',
  maxRow: 0,
  maxCol: 0,
  list: [],
  curSelected: {},

  show: false,

  locationLoading: false,
})

// 取消选中
const tableRef = ref(null)
const cleanSelected = () => {
  data.curSelected = {}
  tableRef.value?.setCurrentRow()
}

// 计算格子
const gridCells = computed({
  get() {
    const cells = []
    if (data.maxRow && data.maxCol) {
      for (let i = 1; i <= data.maxRow; i++) {
        for (let j = 1; j <= data.maxCol; j++) {
          const matched = data.list.find(item => item.seatRow === i && item.seatCol === j)
          cells.push(matched ? matched : { seatRow: i, seatCol: j })
        }
      }
    }
    return cells
  },
  set(val) {
    pageData.detail.users = val.filter(item => item.name)
  },
})

const route = useRoute()
pageActions.getData = async () => {
  await http
    .get(pageData.api, {
      params: {
        meetId: route.query.id,
      },
    })
    .then(res => {
      pageData.detail = res
      pageData.detail.showJobTitle = res.showJobTitle ?? false
      data.list = res?.users ?? []
    })

  await http.get(`/meet/room/${route.query.roomId}`).then(res => {
    data.maxRow = res.maxRow
    data.maxCol = res.maxCol
  })
}

// 选中列表中的人
const handleCurrentChange = row => {
  data.curSelected = row
}

// 处理拖拽结束事件，更新元素的 row 和 col 属性
const onDragEnd = evt => {
  const { newIndex, oldIndex } = evt
  if (newIndex === oldIndex) return
  // 拖动到目标位置
  const targetRow = Math.floor(newIndex / data.maxCol) + 1
  const targetCol = (newIndex % data.maxCol) + 1
  // 拖动的元素
  const draggedItem = gridCells.value[oldIndex]
  // 替换的元素
  const replacedItem = gridCells.value[newIndex]

  replacedItem.seatRow = draggedItem.seatRow
  replacedItem.seatCol = draggedItem.seatCol

  draggedItem.seatRow = targetRow
  draggedItem.seatCol = targetCol
}

const handleAdd = detail => {
  for (let i = 0; i < gridCells.value.length; i++) {
    if (!gridCells.value[i].name) {
      gridCells.value[i] = {
        seatRow: gridCells.value[i].seatRow,
        seatCol: gridCells.value[i].seatCol,
        ...detail,
      }
      break
    }
  }
  gridCells.value = [...gridCells.value] // 用于触发 set 更新
  data.list = gridCells.value.filter(item => item.name)
}

const handleSearch = type => {
  const lists = pageData.detail.users
  if (type === 'reset') {
    data.userName = ''
    data.list = lists
    return
  }
  data.list = lists.filter(item => item.name.includes(data.userName))
}

// 导入导出
const fields = ['mobile', 'name', 'jobTitle', 'company', 'role']
const fieldsEnum = {
  mobile: '手机号',
  name: '人员姓名',
  jobTitle: '职务',
  company: '所属单位',
  role: '参会角色',
}
const onChange = reslut => {
  if (reslut.length > 1) {
    // 清空格子中的数据
    gridCells.value = gridCells.value.map(item => {
      fields.forEach(field => {
        item[field] = ''
      })
      return item
    })

    reslut.slice(1).map(row => {
      const obj = {}
      fields.forEach((field, index) => {
        obj[field] = row[index]
      })
      handleAdd(obj)
    })
  } else {
    ElMessage.error('请上传正确的格式的文件')
  }
}

const exportLoading = ref(false)
const handleExport = () => {
  // 生成表头
  const header = fields.map(field => fieldsEnum[field])
  // 生成每一行的数据
  const rows = pageData.detail.users.map(item => fields.map(field => item[field] ?? ''))
  // 合并
  const result = [header, ...rows]
  exportLoading.value = true
  http({
    url: '/system/file/export-xlsx',
    method: 'POST',
    data: {
      data: result,
    },
  })
    .then(res => {
      const importFileUrl = res.url.slice(res.url.indexOf('/temp/'))
      fetch(importFileUrl, { method: 'GET' })
        .then(response => response.blob())
        .then(blob => {
          const url = window.URL.createObjectURL(blob)
          const a = document.createElement('a')
          a.href = url
          a.download = `${dayjs().format('YYYY-MM-DD_HH_mm_ss')}-人员列表.xlsx`
          document.body.appendChild(a)
          a.click()
          document.body.removeChild(a)
          ElMessage.success('操作成功')
        })
    })
    .finally(() => {
      exportLoading.value = false
    })
}

const handleAddConfirm = detail => {
  data.show = false
  handleAdd({
    jobTitle: detail.jobTitle ?? '',
    ...detail,
  })
}

const handleDelete = row => {
  ElMessageBox.confirm('是否确认删除该成员?', '温馨提示', {
    type: 'warning',
  }).then(() => {
    data.list = pageData.detail.users = pageData.detail.users.filter(item => item.mobile !== row.mobile)
  })
}

const locationRef = ref(null)
const handleResults = () => {
  if (!locationRef.value) return
  data.locationLoading = true
  locationRef.value.style.height = 'auto'
  html2canvas(locationRef.value, {
    useCORS: true,
    allowTaint: true,
    backgroundColor: '#f8f8f8',
  })
    .then(canvas => {
      const dataUrl = canvas.toDataURL('image/png')
      const a = document.createElement('a')
      a.href = dataUrl
      a.download = `${dayjs().format('YYYY-MM-DD_HH_mm_ss')}-会议场位置示意图.png`
      a.click()
      ElMessage.success('操作成功')
    })
    .finally(() => {
      locationRef.value.style.height = '100%'
      data.locationLoading = false
    })
}
</script>

<style lang="scss" scoped>
.meet-user-main {
  height: 100%;
  .job-switch {
    line-height: 25px;
    gap: 10px;
    &__btn {
      height: auto;
    }
  }

  .total-wrapper {
    margin-left: 10px;
  }
  .table-wrapper {
    :deep(.current-row) {
      td.el-table__cell {
        color: var(--el-color-primary);
      }
    }
  }
  &__search {
    display: flex;
    flex-direction: column;
    gap: 20px;
    &--input {
      display: flex;
      align-items: center;
      justify-content: space-between;
      .search-wrapper {
        display: flex;
        gap: 15px;
      }
    }
    &--list {
      flex: 1;
      overflow-y: auto;
    }
  }
  &__right-body {
    height: 100%;
    display: flex;
    flex-direction: column;
    margin-top: 20px;
    width: 1500px;
    gap: 10px;
    .location-header {
      align-items: center;
      color: var(--el-color-danger);
      .export-wrapper {
        gap: 30px;
        font-weight: bold;
        font-size: 18px;
      }
    }
    .location-footer {
      padding: 8px 0;
      background-color: var(--el-color-primary-light-5);
      text-align: center;
      color: #fff;
      font-size: 16px;
      font-weight: bold;
    }
  }
  &__location {
    flex: 1;
    height: 100%;
    min-height: 0;
    &--area {
      width: 100%;
      min-height: 0;
      height: 100%;
    }

    .area-wrapper {
      --location-width: 55px;
      --location-height: 25px;
      position: relative;
      height: 100%;
      overflow: auto;
      background-color: #f8f8f8;
      .area-wrapper--top {
        position: -webkit-sticky;
        position: sticky;
        top: 0;
        left: 50px;
        padding: 10px;
        display: grid;
        grid-template-columns: repeat(var(--location-column), var(--location-width));
        grid-gap: 10px;
        gap: 10px;
        justify-content: center;
        text-align: center;
        background-color: rgba(#000, 0.3);
        color: #fff;
      }
      .area-wrapper--left {
        position: absolute;
        top: 50px;
        left: 0;
        display: grid;
        grid-template-rows: repeat(var(--location-row), var(--location-height));
        grid-gap: 10px;
        gap: 10px;
        line-height: var(--location-height);
        background-color: rgba(#000, 0.3);
        color: #fff;
        text-align: center;
        &-locale {
          width: 40px;
        }
      }
    }

    &-wrapper {
      display: grid;
      grid-template-columns: repeat(var(--location-column), var(--location-width));
      grid-template-rows: repeat(var(--location-row), var(--location-height));
      grid-gap: 10px;
      gap: 10px;
      padding: 10px 20px 20px 40px;
      .location-wrapper-square {
        line-height: var(--location-height);
        background-color: #fff;
        border: 1px solid #35a3ff;
        border-radius: 5px;
        text-align: center;
        user-select: none;
        font-size: 12px;
        &.current-row {
          background-color: #35a3ff;
          color: #fff;
        }
      }
    }
  }
}
</style>
